package com.dz.risk.aspect;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dz.risk.common.utils.DateUtils;
import com.dz.risk.common.utils.JepUtils;
import com.dz.risk.dao.RiskFactorDao;
import com.dz.risk.dao.RiskFactorValueDao;
import com.dz.risk.dao.TemporaryTableOfDataDao;
import com.dz.risk.pojo.domain.RiskFactorBacktracking;
import com.dz.risk.pojo.domain.RiskFactorEntity;
import com.dz.risk.pojo.domain.RiskFactorValueEntity;
import com.dz.risk.pojo.domain.TemporaryTableOfDataEntity;
import com.dz.risk.service.RiskFactorBacktrackingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.*;

/**
 * 风险因子回溯任务处理器
 *
 * @author samsara
 * @date 2021/9/16 17:29
 */
@Component
@EnableScheduling
public class RiskFactorBacktrackingSchedule {

    public static final String ONE = "1";

    public static final String TWO = "2";

    @Autowired
    RiskFactorDao riskFactorDao;

    @Autowired
    TemporaryTableOfDataDao temporaryTableOfDataDao;

    @Autowired
    RiskFactorValueDao riskFactorValueDao;

    @Autowired
    RiskFactorBacktrackingService riskFactorBacktrackingService;


    /**
     * 每天凌晨两点执行一次(计算风险回溯)
     */
    @Scheduled(cron = "${job.riskBack.corn}")
    public void calculateRiskFactorBacktracking() {
        List<RiskFactorEntity> riskFactorEntityList = riskFactorDao.selectRiskFactor();
        // 计算对应的数据
        Calendar versionCal = Calendar.getInstance();
        versionCal.add(Calendar.DATE, -1);
        List<RiskFactorBacktracking> backtrackingList = new ArrayList<>();
        for (RiskFactorEntity riskFactorEntity : riskFactorEntityList) {
            if (Objects.isNull(riskFactorEntity.getExpression())) {
                continue;
            }
            RiskFactorBacktracking riskFactorBacktracking = new RiskFactorBacktracking();
            riskFactorBacktracking.setRiskCode(riskFactorEntity.getRiskCode());
            riskFactorBacktracking.setRiskContent(riskFactorEntity.getRiskContent());
            // 定时器计算的是当前日期前一天
            riskFactorBacktracking.setVersion(DateUtils.dateToStringYears(versionCal.getTime()));
            riskFactorBacktracking.setExpression(riskFactorEntity.getExpression());
            // 回溯值
            Double oneMonthBackValue = null;
            Double twoMonthBackValue = null;
            Double threeMonthBackValue = null;
            // 未来一个月轻
            //获取公式详情
            String formulaDetails = riskFactorEntity.getExpression().getFormulaDetails();
            //获取参与公式计算的参数集合
            List<String> parseFormula = riskFactorEntity.getExpression().getParseFormula();
            List<String> parseFormulaType = riskFactorEntity.getExpression().getParseFormulaType();

            int initialization = (int) (parseFormula.size() / 0.75 + 1);
            //初始化集合容量
            Map<String, Double> paramsMap = new HashMap<>(initialization);

            //根据指标编号以及计算版本设置每个编号对应的值 (未来一个月)
            for (int i = 0; i < parseFormula.size(); i++) {
                String formula = parseFormula.get(i).substring(0, parseFormula.get(i).length() - 2) + i;
                formulaDetails = formulaDetails.replaceFirst(parseFormula.get(i), formula);
                paramsMap.put(formula, getValue(parseFormula.get(i), parseFormulaType.get(i), -1));
            }

            //如果参数值中有为NULL的则不进行计算
            if (!paramsMap.containsValue(null)) {
                //计算公式得出结果值
                oneMonthBackValue = JepUtils.parseExpression(formulaDetails, paramsMap);
            }

            //初始化集合容量
            Map<String, Double> twoMonthsMap = new HashMap<>(initialization);

            //根据指标编号以及计算版本设置每个编号对应的值
            for (int i = 0; i < parseFormula.size(); i++) {
                String formula = parseFormula.get(i).substring(0, parseFormula.get(i).length() - 2) + i;
                twoMonthsMap.put(formula, getValue(parseFormula.get(i), parseFormulaType.get(i), -2));
            }

            //如果参数值中有为NULL的则不进行计算
            if (!twoMonthsMap.containsValue(null)) {
                //计算公式得出结果值
                twoMonthBackValue = JepUtils.parseExpression(formulaDetails, twoMonthsMap);
            }

            //初始化集合容量
            Map<String, Double> threeMonthsMap = new HashMap<>(initialization);

            //根据指标编号以及计算版本设置每个编号对应的值
            for (int i = 0; i < parseFormula.size(); i++) {
                String formula = parseFormula.get(i).substring(0, parseFormula.get(i).length() - 2) + i;
                threeMonthsMap.put(formula, getValue(parseFormula.get(i), parseFormulaType.get(i), -3));
            }

            //如果参数值中有为NULL的则不进行计算
            if (!threeMonthsMap.containsValue(null)) {
                //计算公式得出结果值
                threeMonthBackValue = JepUtils.parseExpression(formulaDetails, threeMonthsMap);
            }

            // 设置回溯值
            if (oneMonthBackValue != null) {
                riskFactorBacktracking.setInTheNextOneMonthsSevereBackValue(String.valueOf(formatDouble(oneMonthBackValue)));
            }

            if (twoMonthBackValue != null) {
                riskFactorBacktracking.setInTheNextTwoMonthsSevereBackValue(String.valueOf(formatDouble(twoMonthBackValue)));
            }

            if (threeMonthBackValue != null) {
                riskFactorBacktracking.setInTheNextThreeMonthsSevereBackValue(String.valueOf(formatDouble(threeMonthBackValue)));
            }

            // 获取阈值
            QueryWrapper<RiskFactorValueEntity> valueEntityQueryWrapper = new QueryWrapper<>();
            valueEntityQueryWrapper.eq("risk_code", riskFactorEntity.getRiskCode());
            valueEntityQueryWrapper.eq("version", DateUtils.dateToStringMonth(new Date()));
            valueEntityQueryWrapper.eq("threshold_flag", 1);
            valueEntityQueryWrapper.orderByDesc("updated_time");
            valueEntityQueryWrapper.last("limit 1");
            RiskFactorValueEntity riskFactorValueEntity = riskFactorValueDao.selectOne(valueEntityQueryWrapper);

            // 设置阈值
            if (riskFactorValueEntity != null) {
                riskFactorBacktracking.setInTheNextOneMonthsSevereThresholdValue(riskFactorValueEntity.getInTheNextOneMonthsSevere());
                riskFactorBacktracking.setInTheNextTwoMonthsSevereThresholdValue(riskFactorValueEntity.getInTheNextTwoMonthsSevere());
                riskFactorBacktracking.setInTheNextThreeMonthsSevereThresholdValue(riskFactorValueEntity.getInTheNextThreeMonthsSevere());
            }
            backtrackingList.add(riskFactorBacktracking);
        }
        riskFactorBacktrackingService.deleteByVersion(DateUtils.dateToStringYears(versionCal.getTime()));
        riskFactorBacktrackingService.saveBatch(backtrackingList);
    }


    public Double getValue(String formula, String type, int month) {
        Double value = null;
        QueryWrapper<TemporaryTableOfDataEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("index_id", formula);
        Long date = 0L;
        // 1: 本日  2: 上月最后一个工作日
        if (type.equals(ONE)) {
            // 计算的是前一天的数据 获取前一天的日期
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.DATE, -1);
            date = DateUtils.dateToLongDate(cal.getTime());
            wrapper.eq("date", date);
            wrapper.orderByDesc("create_time");
            wrapper.last("limit 1");
        } else if (type.equals(TWO)) {
            // 查找中间表传递月的最大的一条数
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.MONTH, month);
            wrapper.apply(" LEFT (date,6) = {0} and date = (select MAX(date) from t_st_temporary_table_of_data where index_id = {1} and LEFT (date,6) = {2})", DateUtils.dateToLongYears(cal.getTime()), formula, DateUtils.dateToLongYears(cal.getTime()));
            wrapper.orderByDesc("create_time");
            wrapper.last("limit 1");
        }
        TemporaryTableOfDataEntity db = temporaryTableOfDataDao.selectOne(wrapper);

        if (db != null) {
            value = Double.parseDouble(db.getIndexValue());
        }

        return value;
    }

    private static String formatDouble(double d) {
        NumberFormat nf = NumberFormat.getInstance();
        //设置保留多少位小数
        nf.setMaximumFractionDigits(4);
        // 取消科学计数法
        nf.setGroupingUsed(false);
        //返回结果
        return nf.format(d);
    }

}
